/*
 * TCPServer.cpp
 *
 *  Created on: 11.05.2010
 *      Author: stg7
 */
// Ein/Ausgabe
#include <iostream>
// Socketkram
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// Client
#include "ClientThread.cpp"

class TCPServer{
private:
	/**
	 * Server socketID
	 */
	int socketID;

	/**
	 *  counter für die Threads
	 */
	int cThreads;
	/**
	 * eingehende Clienten "behandeln" bzw bearbeiten
	 *
	 * @param clientSocketID Client Socket
	 */
	void handleClient(int clientSocketID){
		/**
		 * der Dispatcher soll nun für jeden angemeldeten Clienten
		 * einen neuen Thread für die jeweilige Clientenbehandlung öffnen
		 * dazu dient die Klasse ClientThread
		 *
		 */
		ClientThread* ct=new ClientThread(clientSocketID);
		ct->start();
		cThreads++;
	}
public:
	/**
	 * Starten des Servers
	 *
	 *
	 * @return
	 * 	0= alles ok
	 * 	1= Socket Fehler
	 *  2= Bind Fehler
	 *  3= Listen Fehler
	 */
	int start(){
		cThreads=0;

		socketID = socket(PF_INET, SOCK_STREAM, 0);
		/** Parameter des socket Aufrufes:
		 *
		 * socket ( protokollfamilie, typ, unterprotokoll)
		 *
		 * im BSP:
		 *
		 * 	PF_INET = Internetprotokollfamilie
		 * 	SOCK_STREAM = für TCP
		 * 		( alternativ SOCK_DGRAM für Datagramm (UDP)
		 *
		 *  0 = für Standartprotokoll, der Familie
		 */

		// falls ein Fehler aufgetreten ist, diesen melden und abbrechen
		if (socketID == -1)	{
		    std::cout<<"Error: Socket could not be created"<<std::endl;
			return 1;
		}

		// adresse "bauen"
		struct sockaddr_in addr;
		addr.sin_addr.s_addr = INADDR_ANY ; //alle adressen zulassen
		addr.sin_port =  htons(12346); // Port auf dem "gehorcht" wird
		addr.sin_family = AF_INET; // Protokollfamilie angeben

		/// if the port is block reuse them 
		int opt = 1;
		if(setsockopt(socketID, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) == -1) {
			
			
		} 
	
		// "Binden" des sockets an die Adresse
		if (bind(socketID, (struct sockaddr*) &addr, sizeof(addr)) == -1){
				std::cout<<"Error: Bind error"<<std::endl;
			    return 2;
		}

		// Socket in den Listening-Mode versetzen,
		// das heißt er wartet auf eingehende Verbindungen.
		// 3 = Anzahl der Verbindungen in der Warteschlange
		if (listen(socketID, 3) == -1){
				std::cout<<"listen () failed"<<std::endl;
			    return 3;
		}
		return 0; // kein fehler aufgetreten
	}
	/**
	 * Wait for Clients
	 * 	= auf Clienten Warten , in einer Endlosschleife
	 */
	void wait4Clients(){
		// endlosschleife
		while(1==1){

			// Variable für client adresse
			struct sockaddr_in cli;
			socklen_t cli_size;

			cli_size = sizeof(cli);

			int clientSocketID;
			/**
			 * accept =holt eine eingehende Verbindung aus der Warteschlange
			 *		(blockierend)
			 * Parameter:
			 * 	accept( socketID, clientAdresse, GrößeDerAdresse)
			 *
			 *	liefert -1 falls fehler aufgetreten sind
			 */
			if ((clientSocketID = accept(socketID, (struct sockaddr*) &cli, &cli_size)) != -1) {
				std::cout<<"Client from "<<inet_ntoa(cli.sin_addr)<<" Thread: "<<cThreads<<std::endl;
				handleClient(clientSocketID);
			}
		}
		close(socketID);
	}
};


